﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Argos.WorkflowServices;
using Argos.Workflows;
using Argos.Diagnostics;
using System.Diagnostics;

namespace Argos.Activities
{
	[Description("This activity is used to execute a target test. In order to work properly, this test should be hosted in a target monitoring workflow.")]
	public partial class ExecuteTestActivity: Activity
	{

		#region #ctor: public ExecuteTestActivity()

		/// <summary>
		/// Creates a new instance of the class.
		/// </summary>
		public ExecuteTestActivity()
		{
			InitializeComponent();
		}

		#endregion



		#region public object TestState { get; set; }

		public static readonly DependencyProperty TestStateProperty = DependencyProperty.Register("TestState", typeof(object), typeof(ExecuteTestActivity));

		[Description("Contains the state for the test executed in this activity.")]
		[DefaultValue(null)]
		[Browsable(false)]
		public object TestState
		{
			get { return this.GetValue(TestStateProperty); }
			set { this.SetValue(TestStateProperty, value); }
		}

		#endregion



		#region protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)

		/// <summary>
		/// Executes the activity by resolving the target monitoring workflow in which this activity is
		/// a child activity and executes the test for that target.
		/// </summary>
		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			ITestExecutionService testExecService = executionContext.GetService<ITestExecutionService>();
			if (null == testExecService)
			{
				throw new InvalidOperationException(string.Format("The current workflow runtime does not contain a service that implements interface '{0}', which is required for test execution. Cannot execute tests.", typeof(ITestExecutionService)));
			}

			ITargetMonitoringWorkflow monitoringWorkflow = this.FindParentActivity<ITargetMonitoringWorkflow>();

			Tracer.TraceData(TraceEventType.Information, 0, "Running test for target.", Tracer.CreateData("TargetId", monitoringWorkflow.TargetId));

			try
			{
				this.TestState = testExecService.RunTest(monitoringWorkflow.TargetId);

				if (monitoringWorkflow is ITargetChangeMonitoringWorkflow)
				{
					object previousState = ((ITargetChangeMonitoringWorkflow)monitoringWorkflow).CurrentTestState;
					((ITargetChangeMonitoringWorkflow)monitoringWorkflow).PreviousTestState = previousState;
					((ITargetChangeMonitoringWorkflow)monitoringWorkflow).CurrentTestState = this.TestState;

					if (((ITargetChangeMonitoringWorkflow)monitoringWorkflow).IsChanged(this.TestState, previousState))
					{
						((ITargetChangeMonitoringWorkflow)monitoringWorkflow).HandleChange(this.TestState, previousState);
					}
				}

				if (monitoringWorkflow is ITargetFailureMonitoringWorkflow)
				{
					((ITargetFailureMonitoringWorkflow)monitoringWorkflow).HandleTestSuccess();
				}
			}
			catch (Exception ex)
			{
				if (monitoringWorkflow is ITargetFailureMonitoringWorkflow)
				{
					((ITargetFailureMonitoringWorkflow)monitoringWorkflow).HandleTestFailure(ex);
				}
			}

			Tracer.TraceData(TraceEventType.Information, 0, "Test run completed.", Tracer.CreateData("TargetId", monitoringWorkflow.TargetId));

			return ActivityExecutionStatus.Closed;
		}

		#endregion

		#region protected override void Initialize(IServiceProvider provider)

		protected override void Initialize(IServiceProvider provider)
		{
			base.Initialize(provider);

			if (null == this.FindParentActivity<ITargetMonitoringWorkflow>())
				throw new NotSupportedException(string.Format("The activity '{0}' can only be hosted in a workflow of type '{1}'.", this.GetType(), typeof(ITargetMonitoringWorkflow)));
		}

		#endregion

	}
}
